viz = {
mutable type = 0
const svg = d3.create('svg').attr('class', 'svg-vis').attr("viewBox", [0, 0, width_c, height])
const south_asian_countries = ['Indonesia', 'Philippines', 'Thailand', 'Vietnam', 'Malaysia']
const projection = d3.geoEquirectangular().fitSize([width_c, height], mapGeoJson)
const wrapper = svg.append('g')
let geoGenerator = d3.geoPath().projection(projection)
let regions = wrapper.selectAll('region').data(mapGeoJson.features)
let areas = regions.enter().append('path').attr('class', 'areas').attr('d', d=>geoGenerator(d)).attr('fill','#969696').attr('opacity', 0)
const nodes = wrapper.selectAll('circle').data(nodes_data).join('circle').attr('r', node_radius).attr('fill', 'gray').attr('stroke', 'whitesmoke').attr('stroke-width', 0.2)
const river_group = wrapper.append('g').attr('opacity', 0)
const xAxisGroup = river_group.append('g').attr('transform', `translate(${0}, ${height - (height/3)})`).call(xAxisAllRivers).selectAll("text").attr("dy", "-8px").attr("dx", "-5px").style("text-anchor", "end").attr("transform", "rotate(-90)")
const riverbar = river_group.append('g').attr('transform', `translate(${0}, ${(0)})`)
.selectAll('rect').data(all_rivers_plastic1).join('rect')
.attr('y', v => y_all_rivers(v["Share of global plastics emitted to ocean"]))
.attr('x', v => x_all_rivers(v["Entity"]))
.attr('height', v => y_all_rivers(0) - y_all_rivers(v["Share of global plastics emitted to ocean"]))
.attr('width', x_all_rivers.bandwidth()-3)
.attr('fill', v => v.ph ? "red" : "gray")
const yAxisGroup = river_group.append('g')
.attr('transform', `translate(${margin.right}, ${0})`).call(yAxisAllRivers)
.call(g => g.append('text')
.attr('opacity', 0.8)
.attr('x', 10)
.attr('y', margin.top)
.attr('fill','gray')
.attr('font-weight', 'bold')
.attr('font-size', "0.50rem")
.attr('text-anchor', 'start')
.text('% of Plastic Emission Contribution'))
// // init simulation
const simulation = d3.forceSimulation();
simulation.nodes(nodes_data);
simulation.force('charge', d3.forceManyBody().strength(0))
.force('collision', d3.forceCollide().radius(d => node_radius+0.5).iterations(10)).stop()
const annotate_node = wrapper.append("g")
.attr('transform', `translate(${(width_c/4-5)}, ${(height/3) - 2})`)
annotate_node.append('path')
.attr('d', generateArrow( -200, 0, 0, 0, 5, 1, 1))
.style('fill', 'none')
.style('stroke', 'black');
annotate_node.append('text').text('Each Dot = 1000 Tones of Trash').attr('x', -200).attr('dy', -9).attr('class', 'annotate_node')
const countries_bar = wrapper.append("g")
.attr('transform', `translate(${margin.left}, ${height - (height/4)})`).call(yAxisCountries)
.selectAll("text")
.style("text-anchor", "end").attr('opacity', 1).attr("dy", "-16px").attr("dx", "-15px")
.attr("transform", "rotate(-90)");
const scatter_group = wrapper.append('g')
const scatter_X_axis =scatter_group.append('g').attr('opacity', 0.8)
.attr('transform', `translate(0, ${height/2})`)
.call(scatterXAxis)
.call(g => g.append('text')
.attr('opacity', 0.8)
.attr('x', width_c - 200)
.attr('y', 20)
.attr('fill','gray')
.attr('font-weight', 'bold')
.attr('font-size', "0.61rem")
.attr('text-anchor', 'start')
.text('→ GDP per Capita (Purchasing Power)'))
scatter_group.append("g").attr("transform", `translate(${width_c - (width_c/3)}, ${height/3})`)
.call(circleLegend);
const scatter_Y_axis = scatter_group.append('g').attr('opacity', 0.8)
.attr('transform', `translate(${margin.left}, 0)`)
.call(scatterYAxis)
.call(g => g.append('text')
.attr('opacity', 0.8)
.attr('x', 10)
.attr('y', 20)
.attr('fill','gray')
.attr('font-weight', 'bold')
.attr('font-size', "0.61rem")
.attr('text-anchor', 'start')
.text('Total Plastic Emission ↑'))
const circleScatter = wrapper.append("g")
.attr("stroke", "whitesmoke")
.attr("stroke-opacity", 1.2)
.selectAll("circle")
.data(plastic_dataset)
.enter().append("circle")
.attr("cx", d => xScaleScatter(d.GDP_per_capita))
.attr("cy", d => yScaleScatter(d.pw_total))
.attr('fill', d => { if (south_asian_countries.includes(d.Entity)) {
return 'red'
} else {
return 'gray'
}})
.attr('opacity', 0.5)
.on("mousemove", (event, val) => mouseover_animation(val,event)).on("mouseout", (d) => {
tooltip.style("visibility",'hidden')
})
const mouseover_animation = (val, event) => {
tooltip.style("visibility", "visible").style("top", (event.y-10)+"px").style("left",(event.x+10)+"px")
.html("<div><p>Country: " + val.Entity + "</p>"
+"<p>Plastic Waste Total: " + (val.pw_total/1000).toFixed(2) + "k</p>"
+"</div>")
}
const scatterText = scatter_group.append("g")
.selectAll("text")
.data(plastic_dataset)
.enter().append("text")
.attr("x",d => xScaleScatter(d.GDP_per_capita))
.attr("y", d => yScaleScatter(d.pw_total))
.attr("dy", d => (sizeScale(d.mismanaged_pw_capita)+10))
.style("font-size", d => Math.max(10,sizeScale(d.mismanaged_pw_capita) * 0.4))
.style("text-anchor", "middle")
.attr('fill', d => { if (south_asian_countries.includes(d.Entity)) {
return "red"
} else {
return 'gray'
}})
.text(function(d) { return d.Entity; });
return Object.assign (
html`
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald">
<div class="container">
<div class="controls">
<p>Visualization Controls</p>
<div>
<Button class="button-style" id="prev-slide">Previous Slide</Button>
<Button class="button-style" id="next-slide">Next Slide</Button>
<Button class="button-style" id="reset">Reset</Button>
</div>
</div>
<div class='annotation-section' id="annotation-sec">
${viz_descriptions}
</div>
${svg.node()}
</div>`,
{
morph(type) {
d3.select('.annotation-section').style('max-height', width*0.6 + "px")
d3.selectAll('.desc-section').style('height', width*0.6 + "px")
if (type == 0) {
nodes.attr('transform', function(d) {
return `translate(${width_c/2},${height/2 })`})
// Nodes
simulation.stop()
// nodes.transition()
// .duration(800)
// .attr('r', node_radius)
// .attr('opacity', 0)
// .attr('transform', d => `translate(${Math.random() * width_c },${0})`).attr('fill', 'gray')
// Nodes
simulation.force('charge', d3.forceManyBody().strength(-5))
.force('collision', d3.forceCollide().radius(d => Math.ceil(Math.random()*10, 3)).strength(1))
.force('center', d3.forceCenter(width_c/2, height/2).strength(1))
.force('y', d3.forceY().y(height/2).strength(1))
.force('x', d3.forceX().x(width_c/2).strength(1))
simulation.on('tick', () => {
nodes.transition().duration(1500).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${d.x},${ d.y })`}).attr("fill", 'gray').attr('opacity', 0.6).attr('r', d => Math.ceil(Math.random()*10, 3))})
simulation.velocityDecay(0.3).alpha(1).restart()
// hide
annotate_node.transition().attr('opacity', 0)
scatter_group.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
countries_bar.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
river_group.transition().attr('opacity', 0)
} else if (type == 1) {
// Nodes
simulation.force('charge', d3.forceManyBody().strength(0))
.force('collision', d3.forceCollide().radius(d => node_radius+0.5).iterations(10))
.force('charge', d3.forceManyBody().strength(0)).force('center', d3.forceCenter(width_c/2, height/2).strength(0)).stop()
nodes.transition().duration(1500)
.attr('opacity', 1)
.attr('transform', d => `translate(${d.x_grid},${d.y_grid})`).attr('fill', 'gray').attr("r",node_radius);
annotate_node.transition().attr('opacity',1)
// hide
scatter_group.transition().attr('opacity', 0)
countries_bar.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
} else if (type == 2) {
simulation.stop()
// show
areas.transition().duration(400).attr('opacity', 0.4)
// Nodes
simulation .force('charge', d3.forceManyBody().strength(0))
.force('collision', d3.forceCollide().radius(d => node_radius+0.5).iterations(10))
.force('y', d3.forceY().y(d => d.y_map))
.force('x', d3.forceX().x(d => d.x_map))
simulation.on('tick', () => {
nodes.transition().duration(800).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${d.x},${ d.y})`}).attr('fill', 'gray')
});
simulation.alpha(1).alphaDecay(0.05).velocityDecay(0.25).restart()
// hide
annotate_node.transition().attr('opacity',0)
scatter_group.transition().attr('opacity', 0)
countries_bar.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
} else if (type == 3) {
simulation.stop()
// show
areas.transition().duration(400).attr('opacity', 0.4)
// Nodes
simulation.force('y', d3.forceY().y(d => d.y_map)).force('x', d3.forceX().x(d => d.x_map))
simulation.on('tick', () => {
nodes.transition().duration(800).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${d.x},${ d.y})`}).attr('fill', d => { if (south_asian_countries.includes(d.Entity)) {
return 'red'
} else {
return 'gray'
}})})
simulation.alpha(1).alphaDecay(0.05).velocityDecay(0.25).restart()
// hide
river_group.transition().attr('opacity', 0)
scatter_group.transition().attr('opacity', 0)
countries_bar.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
} else if (type == 4) {
simulation.stop()
// show
countries_bar.transition().attr('opacity', 1)
// Nodes
simulation.force('y', d3.forceY().y(d => x_count(d.count)).strength(4))
.force('x', d3.forceX().x(d => y_countries(d.Entity)).strength(1))
.force('collision', d3.forceCollide().radius(d => node_radius+0.5).iterations(10))
simulation.restart()
simulation.on('tick', () => {
nodes.transition().duration(800).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${d.x + margin.left},${ d.y })`}).attr('fill', d => { if (south_asian_countries.includes(d.Entity)) {
return 'red'
} else {
return 'gray'
}}).attr('opacity', 1)})
simulation.alpha(1).alphaDecay(0.1).velocityDecay(0.36).restart()
// hide
river_group.transition().attr('opacity', 0)
scatter_group.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
} else if (type == 5) {
simulation.stop()
// show
countries_bar.transition().attr('opacity', 1)
// Nodes
simulation.force('y', d3.forceY().y(d => x_count(d.count)).strength(4))
.force('x', d3.forceX().x(d => y_countries(d.Entity)).strength(1))
.force('collision', d3.forceCollide().radius(d => node_radius+0.5).iterations(10))
simulation.restart()
simulation.on('tick', () => {
nodes.transition().duration(800).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${d.x + margin.left},${ d.y })`}).attr('fill', d => { if (d.Entity == 'Philippines') {
return 'red'
} else {
return 'gray'
}}).attr('opacity', 1)})
simulation.alpha(1).alphaDecay(0.1).velocityDecay(0.36).restart()
// hide
river_group.transition().attr('opacity', 0)
scatter_group.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
} else if (type == 6) {
simulation.stop()
// show
scatter_group.transition().attr('opacity', 1)
circleScatter.transition().duration(5000).attr("r", d => sizeScale(d.mismanaged_pw_capita));
// Nodes
nodes.transition().delay((d, i) => i * (Math.random() * 5)).duration(Math.random() * 500).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${xScaleScatter(d.GDP_per_capita)},${yScaleScatter(d.pw_total)})`}).transition().attr('opacity', 0)
// hide
river_group.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
countries_bar.transition().attr('opacity', 0)
} else if (type == 7) {
simulation.stop()
nodes.transition()
.duration(800)
.attr('r', node_radius)
.attr('opacity', 0)
.attr('transform', d => `translate(${Math.random() * width_c},${0})`).attr('fill', "gray")
river_group.transition().attr('opacity', 1)
// hide
scatter_group.transition().attr('opacity', 0)
countries_bar.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
} else if (type == 8) {
// Nodes
simulation.stop()
nodes.transition().duration(800)
.attr('opacity', 1)
.attr('transform', d => `translate(${d.x_grid},${d.y_grid})`).attr('fill', "red")
.transition().delay((d, i) => i * (Math.random() * 30)).duration(Math.random() * 1500)
.attr('transform', d => `translate(${d.x_grid},${width_c})`).attr('opacity', 0)
// hide
river_group.transition().attr('opacity', 0)
scatter_X_axis.transition().attr('opacity', 0)
scatter_Y_axis.transition().attr('opacity', 0)
countries_bar.transition().attr('opacity', 0)
scatterText.transition().attr('opacity', 0)
areas.transition().attr('opacity', 0)
// hide
scatter_group.transition().attr('opacity', 0)
circleScatter.transition().duration(800).attr("r",0);
}
}
})
}